package com.sunda.spmswms.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunda.spmscommon.ConstantWhsOther;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmswms.entity.WhsOtherDtl;
import com.sunda.spmswms.entity.WhsOtherTask;
import com.sunda.spmswms.mapper.WhsOtherTaskMapper;
import com.sunda.spmswms.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import static com.sunda.spmscommon.Constans.*;
import static com.sunda.spmscommon.ConstantWhsOther.sendToSAPCancel;
import static com.sunda.spmscommon.ConstantWhsOther.sendToSAPCancelError;
import static com.sunda.spmscommon.constant.CommonConstant.WHS_OTHER_TASK_CANCEL;
import static com.sunda.spmscommon.constant.CommonConstant.WHS_OTHER_TASK_DONE;

/**
 * <p>
 * 异常出入库任务表 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-06-16
 */
@Slf4j
@Service
public class WhsOtherTaskCancelServiceImpl extends ServiceImpl<WhsOtherTaskMapper, WhsOtherTask> implements IWhsOtherTaskCancelService {

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;
    @Autowired
    IWhsInventoryInfoService iWhsInventoryInfoService;
    @Autowired
    ISapDeliveryNoteLogService iSapDeliveryNoteLogService;
    @Autowired
    IWhsOperateLogService iWhsOperateLogService;
    @Autowired
    IWhsOtherDtlService iWhsOtherDtlService;
    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    /** 其他出入库 撤销 功能；
     * 单据状态说明：0-作废 1-草稿 2-操作中 3-待提交SAP 4-提交SAP成功 5-提交SAP失败 6-关闭 7-已撤销；
     * 状态 6 时，撤销需要提交SAP，扣减库存，成功则状态更新为 7-已撤销；失败则忽略状态更新；
     * */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult cancelWhsOtherTask(String userId, String whsOtherUuid, String cancelDate, String cancelRemark) {
        if (StringUtils.isEmpty(whsOtherUuid) || StringUtils.isEmpty(cancelDate)){
            return ResponseResult.error("请求参数错误");
        }
        QueryWrapper<WhsOtherTask> queryWrapper = new QueryWrapper<WhsOtherTask>().eq("UUID", whsOtherUuid);
        WhsOtherTask whsOtherTask = this.baseMapper.selectOne(queryWrapper);
        List<WhsOtherDtl> whsOtherDtlList = iWhsOtherDtlService.getWhsOtherDtlList(whsOtherUuid);
        ResponseResult resp = checkCancelWhsOtherTaskValidate(whsOtherTask, whsOtherDtlList);
        if (resp.getCode() != SUCCESS){
            return resp;
        }

        /** 其他出入库 - 海运出库 - 撤销功能 — 把东西从仓库加回来；海运出库SAP撤销，只需输入 装箱单号、SPMS出库任务uuid即可，不用传输明细行； */
        if (whsOtherTask.getMovementType().equals(ConstantWhsOther.OutHouseByShip)){
            JSONObject dataToSap = cancelZ641DataToSapFormat(whsOtherTask);
            log.info("\n装箱单出库结果删除接口\ndataToSap ====== " + dataToSap);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon((dataToSap)));
            log.info("\n装箱单出库结果删除接口\nmessage ====== " + message);
            if (message.containsKey("RESPONSE") && message.getJSONObject("RESPONSE").containsKey("RETURN_DATA")
                    && SUBMIT_SAP_SUCCESS.equals(message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("EX_TYPE"))){
                updateWhsOtherTask(whsOtherTask, WHS_OTHER_TASK_CANCEL, cancelDate, cancelRemark, "", "");
                ResponseResult updateWhsStorageInventoryResult =  updateWhsStorageInventory(whsOtherTask, whsOtherDtlList, userId);
                iSapDeliveryNoteLogService.insertSapRequestRecord(whsOtherUuid, userId, sendToSAPCancel, message.toJSONString(), dataToSap.toJSONString());
                if (!SUCCESS.equals(updateWhsStorageInventoryResult.getCode())){
                    throw new RuntimeException("提交SAP成功后更新 SPMS 库存失败：" + updateWhsStorageInventoryResult.getData());
                }
                return ResponseResult.success().add("dataToSap", dataToSap)
                        .add("sapReturnedData", message)
                        .add("whsOtherTask", this.baseMapper.selectOne(queryWrapper));
            }else {
                iSapDeliveryNoteLogService.insertSapRequestRecord(whsOtherUuid, userId, sendToSAPCancelError, message.toJSONString(), dataToSap.toJSONString());
                return ResponseResult.error().add("dataToSap", dataToSap).add("sapReturnedData", message);
            }
        }

        /** 其他出入库 - 卸货入库 - 撤销功能 — 把东西从仓库撤出去 */
        if (whsOtherTask.getMovementType().equals(ConstantWhsOther.InHouseUnload)){
            List<Map<String, Object>> dataToSapItemsM = this.baseMapper.getCancelWhsOtherTaskItemsM(whsOtherUuid);
            if (dataToSapItemsM == null || dataToSapItemsM.size() == 0){
                return ResponseResult.error("请求参数能被撤销的有效行数据为0，撤销失败");
            }
            JSONObject dataToSap = cancel311DataToSapFormat(whsOtherTask, cancelRemark, cancelDate, dataToSapItemsM);
            System.out.println("其他出入库 - 卸货入库 - 撤销功能 dataToSap:" + dataToSap);
            JSONObject sapReturnedData = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            System.out.println("其他出入库 - 卸货入库 - 撤销功能 sapReturnedData:" + sapReturnedData);
            JSONObject returnData = sapReturnedData.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
            if (SUBMIT_SAP_SUCCESS.equals(returnData.getString("O_TYPE"))){
                updateWhsOtherTask(whsOtherTask, WHS_OTHER_TASK_CANCEL, cancelDate, cancelRemark, returnData.getString("O_MBLNR"), returnData.getString("O_MJAHR"));
                ResponseResult updateWhsStorageInventoryResult =  updateWhsStorageInventory(whsOtherTask, whsOtherDtlList, userId);
                iSapDeliveryNoteLogService.insertSapRequestRecord(whsOtherUuid, userId, sendToSAPCancel, sapReturnedData.toJSONString(), dataToSap.toJSONString());
                if (!SUCCESS.equals(updateWhsStorageInventoryResult.getCode())){
                    throw new RuntimeException("提交SAP成功后更新 SPMS 库存失败：" + updateWhsStorageInventoryResult.getData());
                }
                return ResponseResult.success().add("dataToSap", dataToSap)
                        .add("sapReturnedData", sapReturnedData)
                        .add("whsOtherTask", this.baseMapper.selectOne(queryWrapper));
            } else {
                iSapDeliveryNoteLogService.insertSapRequestRecord(whsOtherUuid, userId, sendToSAPCancelError, sapReturnedData.toJSONString(), dataToSap.toJSONString());
                return ResponseResult.error().add("dataToSap", dataToSap).add("sapReturnedData", sapReturnedData);
            }
        }

        return ResponseResult.error("该移动类型SAP撤销功能尚未完成");
    }


    /** 其他出入库 撤销成功以后库存数据更新 */
    public ResponseResult updateWhsStorageInventory(WhsOtherTask whsOtherTask, List<WhsOtherDtl> whsOtherDtlList, String userId){
        if (whsOtherTask.getMovementType().equals(ConstantWhsOther.InHouseUnload)){
            if ("M".equals(whsOtherTask.getGoodsType())){
                for (WhsOtherDtl whsOtherDtl : whsOtherDtlList){
                    if (whsOtherDtl.getOperateQty() > 0){
                        JSONArray tempStorage = JSONArray.parseArray(whsOtherDtl.getTempStorage());
                        String materialNo = whsOtherDtl.getMaterialNo();
                        for (int i = 0; i < tempStorage.size(); i++){
                            JSONObject storageInfo = tempStorage.getJSONObject(i);
                            String storageUuid = storageInfo.getString("storageUuid");
                            ResponseResult updateWhsStorageInventoryResult = iWhsStorageInventoryService.updateStorageInventoryM(
                                    storageUuid, materialNo, storageInfo.getDoubleValue("qty"), "sub");
                            iWhsOperateLogService.insertWhsOperateLog("2", storageUuid, materialNo, "", storageInfo.getDoubleValue("qty"),
                                    "20", whsOtherTask.getUuid(), GOODS_OUT_STORAGE, userId, WHS_WhsIn_WithdrawM, whsOtherTask.getWerks(), whsOtherTask.getWhsLocationCode());
                            if (!SUCCESS.equals(updateWhsStorageInventoryResult.getCode())){
                                return updateWhsStorageInventoryResult;
                            }
                        }
                    }
                }
                return ResponseResult.success();
            }
        }
        if (whsOtherTask.getMovementType().equals(ConstantWhsOther.OutHouseByShip)) {
            if ("M".equals(whsOtherTask.getGoodsType())) {
                for (WhsOtherDtl whsOtherDtl : whsOtherDtlList){
                    if (whsOtherDtl.getOperateQty() > 0){
                        JSONArray tempStorage = JSONArray.parseArray(whsOtherDtl.getTempStorage());
                        String materialNo = whsOtherDtl.getMaterialNo();
                        for (int i = 0; i < tempStorage.size(); i++){
                            JSONObject storageInfo = tempStorage.getJSONObject(i);
                            String storageUuid = storageInfo.getString("storageUuid");
                            ResponseResult updateWhsStorageInventoryResult = iWhsStorageInventoryService.updateStorageInventoryM(
                                    storageUuid, materialNo, storageInfo.getDoubleValue("qty"), "add");
                            iWhsOperateLogService.insertWhsOperateLog("2", storageUuid, materialNo, "", storageInfo.getDoubleValue("qty"),
                                    "19", whsOtherTask.getUuid(), TRADE_GOODS_INTO_STORAGE, userId, WHS_WhsOut_Withdraw, whsOtherTask.getWerks(), whsOtherTask.getWhsLocationCode());
                            if (!SUCCESS.equals(updateWhsStorageInventoryResult.getCode())){
                                return updateWhsStorageInventoryResult;
                            }
                        }
                    }
                }
                return ResponseResult.success();
            }

            if ("X".equals(whsOtherTask.getGoodsType())) {
                for (WhsOtherDtl whsOtherDtl : whsOtherDtlList){
                    if (whsOtherDtl.getOperateQty() > 0){
                        JSONArray tempStorage = JSONArray.parseArray(whsOtherDtl.getTempStorage());
                        String boxNote = whsOtherDtl.getBoxNote();

                        ResponseResult updateWhsInventoryResult = iWhsInventoryInfoService.updateWhsInventoryX(whsOtherTask.getWerks(), whsOtherTask.getWhsLocationCode(),
                                boxNote, whsOtherDtl.getOperateQty(), "add", userId);
                        iWhsOperateLogService.insertWhsOperateLog("1", "", "", boxNote, whsOtherDtl.getOperateQty(),
                                "1", whsOtherTask.getUuid(), SPARE_PARTS_INTO_WHS, userId, WHS_OUT_WITHDRAW, whsOtherTask.getWerks(), whsOtherTask.getWhsLocationCode());

                        if (!SUCCESS.equals(updateWhsInventoryResult.getCode())){
                            return updateWhsInventoryResult;
                        }

                        for (int i = 0; i < tempStorage.size(); i++){
                            JSONObject storageInfo = tempStorage.getJSONObject(i);
                            String storageUuid = storageInfo.getString("storageUuid");
                            ResponseResult updateWhsStorageInventoryResult = iWhsStorageInventoryService.updateStorageInvX(
                                    storageUuid, boxNote, storageInfo.getDoubleValue("qty"), "add");
                            iWhsOperateLogService.insertWhsOperateLog("2", storageUuid, "", boxNote, storageInfo.getDoubleValue("qty"),
                                    "19", whsOtherTask.getUuid(), SPARE_PARTS_INTO_STORAGE, userId, WHS_OUT_WITHDRAW, whsOtherTask.getWerks(), whsOtherTask.getWhsLocationCode());

                            if (!SUCCESS.equals(updateWhsStorageInventoryResult.getCode())){
                                return updateWhsStorageInventoryResult;
                            }
                        }
                    }
                }
                return ResponseResult.success();
            }
        }
        return ResponseResult.error("该移动类型SAP撤销功能尚未完成");
    }


    /** 其他出入库 撤销功能数据规范性校验 */
    ResponseResult checkCancelWhsOtherTaskValidate(WhsOtherTask whsOtherTask, List<WhsOtherDtl> whsOtherDtlList){
        if (null == whsOtherTask || null == whsOtherTask.getUuid()){
            return ResponseResult.error("其他出入库数据不存在");
        }
        if (null == whsOtherDtlList || whsOtherDtlList.size() == 0){
            return ResponseResult.error("其他出入库明细行不能为空");
        }
        if (StringUtils.isEmpty(whsOtherTask.getTaskStatus()) || !WHS_OTHER_TASK_DONE.equals(whsOtherTask.getTaskStatus())){
            return ResponseResult.error("其他出入库单据当前状态不允许撤销");
        }
        if (whsOtherTask.getMovementType().equals(ConstantWhsOther.OutHouseByShip)){
            if (StringUtils.isEmpty(whsOtherTask.getPackageList())){
                return ResponseResult.error("其他出入库-海运出库 装箱单号不能为空");
            }
            for (WhsOtherDtl whsOtherDtl : whsOtherDtlList){
                if (whsOtherDtl.getOperateQty() > 0){
                    JSONArray tempStorage = JSONArray.parseArray(whsOtherDtl.getTempStorage());
                    if (null == tempStorage || tempStorage.size() == 0){
                        return ResponseResult.error("其他出入库明细行储位信息错误");
                    }
                }
            }
        }

        if (whsOtherTask.getMovementType().equals(ConstantWhsOther.InHouseUnload)){
            if (StringUtils.isEmpty(whsOtherTask.getSapVoucherNumber()) || StringUtils.isEmpty(whsOtherTask.getSapVoucherYear())){
                return ResponseResult.error("其他出入库-卸货入库 SAP凭证号 或 SAP凭证年份 不能为空");
            }
            if (StringUtils.isEmpty(whsOtherTask.getPackageList())){
                return ResponseResult.error("其他出入库-卸货入库 装箱单号不能为空");
            }

            if ("M".equals(whsOtherTask.getGoodsType())){
                for (WhsOtherDtl whsOtherDtl : whsOtherDtlList){
                    if (whsOtherDtl.getOperateQty() > 0){
                        JSONArray tempStorage = JSONArray.parseArray(whsOtherDtl.getTempStorage());
                        String materialNo = whsOtherDtl.getMaterialNo();
                        if (null == tempStorage || tempStorage.size() == 0){
                            return ResponseResult.error("其他出入库明细行物料" + whsOtherDtl.getMaterialNo() + "储位信息错误");
                        }
                        for (int i = 0; i < tempStorage.size(); i++){
                            ResponseResult checkInventoryResult = iWhsStorageInventoryService.checkStorageInventory(tempStorage, materialNo);
                            if (!SUCCESS.equals(checkInventoryResult.getCode())){
                                return checkInventoryResult;
                            }
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    /** 其他出入库 - 海运出库 撤销功能提交SAP数据拼装 */
    JSONObject cancelZ641DataToSapFormat(WhsOtherTask whsOtherTask){
        JSONObject doc = new JSONObject();
        JSONObject request = new JSONObject();
        JSONObject esbAttrs = new JSONObject();
        JSONObject requestData = new JSONObject();
        JSONObject head = new JSONObject();

        esbAttrs.put("App_ID", "SPMS");
        esbAttrs.put("Application_ID", "00020000000002");
        esbAttrs.put("Transaction_ID", UUID.randomUUID().toString());

        head.put("imXdnum", whsOtherTask.getPackageList());
        head.put("imZspmsTaskid", whsOtherTask.getUuid());
        head.put("imImportFlag", "A");

        requestData.put("Head", head);
        requestData.put("Operation", "Z_ZXD_DEL");
        requestData.put("Type", "ZXD_DEL");

        request.put("ESB_ATTRS", esbAttrs);
        request.put("REQUEST_DATA", requestData);
        doc.put("REQUEST", request);
        return doc;
    }

    /** 其他出入库 - 卸货入库 撤销功能提交SAP数据拼装 */
    JSONObject cancel311DataToSapFormat(WhsOtherTask whsOtherTask, String cancelRemark, String cancelDate, List<Map<String, Object>> dataToSapItemsM){
        JSONObject doc = new JSONObject();

        JSONObject request = new JSONObject();
        JSONObject esbAttrs = new JSONObject();
        JSONObject requestData = new JSONObject();
        JSONObject head = new JSONObject();

        esbAttrs.put("App_ID", "SPMS");
        esbAttrs.put("Application_ID", "00020000000002");
        esbAttrs.put("Transaction_ID", UUID.randomUUID().toString());

        head.put("iFlag", "D");
        head.put("iMblnr", whsOtherTask.getSapVoucherNumber());
        head.put("iMjahr", whsOtherTask.getSapVoucherYear());
        head.put("iXdnum", whsOtherTask.getPackageList());
        head.put("iBktxt", StringUtils.isEmpty(cancelRemark) ? "" : cancelRemark);
        head.put("iBldat", "");
        head.put("iBudat", cancelDate.replaceAll("-", ""));

        requestData.put("Items", dataToSapItemsM);
        requestData.put("Head", head);

        requestData.put("Operation", "Z_SPMS_1150");
        requestData.put("Type", "SPMS1150");

        request.put("ESB_ATTRS", esbAttrs);
        request.put("REQUEST_DATA", requestData);

        doc.put("REQUEST", request);
        return doc;
    }

    void updateWhsOtherTask (WhsOtherTask whsOtherTask, String targetStatus, String cancelDate, String cancelRemark,
                             String cancelVoucherNumber, String cancelVoucherYear){
        whsOtherTask.setTaskStatus(targetStatus);
        whsOtherTask.setCancelDate(cancelDate);
        if (StringUtils.isNotEmpty(cancelRemark)){
            whsOtherTask.setCancelRemark(cancelRemark);
        }
        if (StringUtils.isNotEmpty(cancelVoucherNumber)){
            whsOtherTask.setCancelVoucherNumber(cancelVoucherNumber);
        }
        if (StringUtils.isNotEmpty(cancelVoucherYear)){
            whsOtherTask.setCancelVoucherYear(cancelVoucherYear);
        }
        this.baseMapper.update(whsOtherTask, new QueryWrapper<WhsOtherTask>().eq("UUID", whsOtherTask.getUuid()));
    }





    /************************* 以下为 Transactional 异常回滚测试代码忽略 ***************************/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult checkException(String aa, String bb) {
        iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM("123456789", "999947", "Exception Test");
        ResponseResult resp = dataValidate2(aa, bb);
        if (resp.getCode() != SUCCESS){
            throw new RuntimeException("requestError: " + resp.getMsg());
        }
        return ResponseResult.success();
    }

    public ResponseResult dataValidate2(String aa, String bb){
        try {
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM("123456789", "999947", "dataValidate2");
            ResponseResult resp = dataValidate3(aa, bb);
            if (resp.getCode() != SUCCESS){
                throw new RuntimeException(resp.getMsg());
            }
            return ResponseResult.success();
        } catch (Exception e){
            e.printStackTrace();
            return ResponseResult.error(e.getMessage());
        }
    }

    public ResponseResult dataValidate3(String aa, String bb){
        try {
            System.out.println("aa = " + aa + "    bb = " + bb);
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM("123456789", "999947", "dataValidate3");
            if (StringUtils.isEmpty(aa)){
                throw new Exception("dataValidate3 抛出异常 dataValidate");
            }
            return ResponseResult.success();
        } catch (Exception e){
            e.printStackTrace();
            return ResponseResult.error(e.getMessage());
        }
    }
}



